package com.pig4cloud.pig.village.reward.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pig.village.api.app.MainReward;
import com.pig4cloud.pig.village.api.dto.ImageDto;
import com.pig4cloud.pig.village.api.dto.RewardInfoDTO;
import com.pig4cloud.pig.village.api.entity.*;
import com.pig4cloud.pig.village.api.request.RewardAdd;
import com.pig4cloud.pig.village.api.request.RewardSearch;
import com.pig4cloud.pig.village.api.request.RewardUpdate;
import com.pig4cloud.pig.village.collect.service.ICollectInfoService;
import com.pig4cloud.pig.village.family.service.IFamilyService;
import com.pig4cloud.pig.village.file.service.IImageService;
import com.pig4cloud.pig.village.reward.mapper.RewardMapper;
import com.pig4cloud.pig.village.reward.service.IRewardEventService;
import com.pig4cloud.pig.village.reward.service.IRewardService;
import com.pig4cloud.pig.village.reward.service.IRewardSolutionService;
import com.pig4cloud.pig.village.rules.service.IRuleService;
import com.pig4cloud.pig.village.sequence.service.ISequenceService;
import com.pig4cloud.pig.village.team.service.ITeamService;
import com.pig4cloud.pig.village.villager.service.IVillagerService;
import com.pig4cloud.pig.village.welfare.service.IWelfareService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author limbray.li
 * @date 2021/6/26
 */
@Service
@Slf4j
public class RewardServiceImpl extends ServiceImpl<RewardMapper, RewardInfo> implements IRewardService {
	@Resource
	private IRewardEventService rewardEventService;
	@Resource
	private IRewardSolutionService rewardSolutionService;
	@Resource
	private IImageService imageService;
	@Resource
	private ITeamService teamService;
	@Resource
	private IFamilyService familyService;
	@Resource
	private IVillagerService villagerService;
	@Resource
	private IWelfareService welfareService;
	@Resource
	private ISequenceService sequenceService;
	@Resource
	private ICollectInfoService collectInfoService;
	@Resource
	private IRuleService ruleService;

	@Override
	@Transactional
	public boolean addReward(RewardAdd rewardAdd) {
		//先保存事件
		RewardEvent event = RewardEvent.builder()
				.eventDesc(rewardAdd.getEventDesc())
				.eventTime(rewardAdd.getEventTime())
				.address(rewardAdd.getAddress())
				.eventNum(getEventNum())
				.month(rewardAdd.getEventTime().getMonthValue())
				.timeDimension(2)
				.year(rewardAdd.getEventTime().getYear())
				.build();
		rewardEventService.save(event);
		if (rewardAdd.getFiles() != null && rewardAdd.getFiles().length > 0) {
			//再保存图片
			imageService.saveFiles(1, event.getId(), rewardAdd.getFiles());
		}
		if (rewardAdd.getSign() != null) {
			//保存签名
			imageService.saveFiles(2, event.getId(), rewardAdd.getSign());
		}

		// To get the sub_welfare_name
		Welfare welfareForTheEvent = welfareService.getById(rewardAdd.getWelfareId());

		//最后保存红黑榜
		RewardInfo info = RewardInfo.builder()
				.welfareId(rewardAdd.getWelfareId())
//				.amountFamily(getAmountFamily())
//				.amountTeam(getAmountTeam())
				.eventId(event.getId())
				.teamId(rewardAdd.getTeamId())
				.familyId(rewardAdd.getFamilyId())
//				.villagerId(rewardAdd.getUser())
				.villagerId(rewardAdd.getRewardUserId())
				.year(rewardAdd.getEventTime().getYear())
				.month(rewardAdd.getEventTime().getMonthValue())
				.date(rewardAdd.getEventTime())
				.punishment(rewardAdd.getPunishment())
				.violationSubCode(welfareForTheEvent.getSubWelfareCode())
				.build();
		super.save(info);
		nextStep(event, info);
		return true;
	}

	private void nextStep(RewardEvent event, RewardInfo info) {
		//TODO 观察者模式，触发事件：推送待审批消息等
		ruleService.dealRuleByEvent(event, info);
	}

	/**
	 * 获取事件编号
	 *
	 * @return
	 */
	private String getEventNum() {
		String name = DatePattern.PURE_DATE_FORMAT.format(new Date());
		return name + "-" + sequenceService.nextNum(name, 1);
	}

	/**
	 * TODO 统计户考核的金额
	 *
	 * @return
	 */
	private BigDecimal getAmountFamily() {
		return new BigDecimal(200);
	}

	/**
	 * TODO 统计队考核的金额
	 *
	 * @return
	 */
	private BigDecimal getAmountTeam() {
		return new BigDecimal(200);
	}

	@Override
	public IPage<RewardInfoDTO> pageBySearch(Page page, RewardSearch search) {
		//查询红黑榜数据
		IPage<RewardInfo> infoPage = getRewardInfo(page, search);
		List<RewardInfo> infoList = infoPage.getRecords();
		if (CollectionUtils.isEmpty(infoList)) {
			return infoPage.convert(e -> null);
		}
		Set<Long> eventIdList = infoList.stream().map(e -> e.getEventId()).collect(Collectors.toSet());
		Set<Long> infoIdList = infoList.stream().map(e -> e.getId()).collect(Collectors.toSet());
		Set<Long> teamIdList = infoList.stream().map(e -> e.getTeamId()).collect(Collectors.toSet());
		Set<Long> familyIdList = infoList.stream().map(e -> e.getFamilyId()).collect(Collectors.toSet());
		Set<Long> villagerIdList = infoList.stream()
				.map(e -> Arrays.asList(e.getVillagerId()))
				.flatMap(e -> e.stream())
				.collect(Collectors.toSet());
		Set<Long> welfareIdList = infoList.stream().map(e -> e.getWelfareId()).collect(Collectors.toSet());
		//查询事件数据
		List<RewardEvent> events = rewardEventService.listByIds(eventIdList);
		Map<Long, RewardEvent> eventMap = events.stream().collect(Collectors.toMap(RewardEvent::getId, Function.identity(), (v1, v2) -> v2));
		//查询处理结果,按红黑榜数据维度存储！
		List<RewardSolution> solutions = rewardSolutionService.getSolutions(null, infoIdList);
		Map<Long, RewardSolution> solutionMap = solutions.stream().collect(Collectors.toMap(RewardSolution::getInfoId, Function.identity(), (v1, v2) -> v2));
		//查询图片信息
		List<VillageImage> images = imageService.getImages(1, eventIdList);
		Map<Long, List<VillageImage>> imagesMap = images.stream().collect(Collectors.groupingBy(VillageImage::getOutKey));
		List<VillageImage> signs = imageService.getImages(2, eventIdList);
		Map<Long, VillageImage> signMap = signs.stream().collect(Collectors.toMap(VillageImage::getOutKey, Function.identity(), (v1, v2) -> v2));
		//查询队
		List<Team> teams = teamService.listByIds(teamIdList);
		Map<Long, Team> teamMap = teams.stream().collect(Collectors.toMap(Team::getId, Function.identity(), (v1, v2) -> v2));
		//查询户
		List<Family> familys = familyService.listByIds(familyIdList);
		Map<Long, Family> familyMap = familys.stream().collect(Collectors.toMap(Family::getId, Function.identity(), (v1, v2) -> v2));
		//查询户
		List<Villager> villagers = villagerService.listByIds(villagerIdList);
		Map<Long, Villager> villagerMap = villagers.stream().collect(Collectors.toMap(Villager::getId, Function.identity(), (v1, v2) -> v2));
		//查询福利信息
		List<Welfare> welfares = welfareService.listByIds(welfareIdList);
		Map<Long, Welfare> welfareMap = welfares.stream().collect(Collectors.toMap(Welfare::getId, Function.identity(), (v1, v2) -> v2));
		//组装数据
		IPage<RewardInfoDTO> resultList = infoPage.convert(e -> {
			RewardInfoDTO dto = new RewardInfoDTO();
			RewardEvent event = eventMap.get(e.getEventId());
			RewardSolution solution = solutionMap.get(e.getId());
			List<VillageImage> imageList = imagesMap.get(e.getEventId());
			VillageImage sign = signMap.get(e.getEventId());
			Team team = teamMap.get(e.getTeamId());
			Family family = familyMap.get(e.getFamilyId());
			Welfare welfare = welfareMap.get(e.getWelfareId());
			BeanUtil.copyProperties(e, dto);
			if (event != null) {
				dto.setEventNum(event.getEventNum());
				dto.setEventDesc(event.getEventDesc());
			}
			if (solution != null) {
				dto.setEventResult(solution.getEventResult());
				dto.setEventImprove(solution.getEventImprove());
			}
			if (CollectionUtils.isNotEmpty(imageList)) {
				List<ImageDto> imageDtos = imageList.stream().map(k -> {
					return ImageDto.builder()
							.fileName(k.getFileName())
							.url(k.getUrl())
							.build();
				}).collect(Collectors.toList());
				dto.setUrlList(imageDtos);
			}
			if (sign != null) {
				ImageDto imageDto = ImageDto.builder()
						.fileName(sign.getFileName())
						.url(sign.getUrl())
						.build();
				dto.getUrlList().add(imageDto);
			}
			if (team != null) dto.setTeamName(team.getTeamName());
			if (family != null) dto.setFamilyName(family.getFamilyName());
			if (family != null && villagerMap.get(family.getLeader()) != null)
				dto.setFamilyLeader(villagerMap.get(family.getLeader()).getName());
//			if (villagerMap.get(e.getCheckUser()) != null)
//				dto.setCheckUserName(villagerMap.get(e.getCheckUser()).getName());
			if (villagerMap.get(e.getVillagerId()) != null)
				dto.setVillager(villagerMap.get(e.getVillagerId()).getName());
			if (welfare != null) dto.setWelfareName(welfare.getWelfareName());
			return dto;
		});
		return resultList;
	}

	private IPage<RewardInfo> getRewardInfo(Page page, RewardSearch search) {
		LambdaQueryWrapper<RewardInfo> query = Wrappers.lambdaQuery();
		query.le(search.getTimeBegin() != null, RewardInfo::getDate, search.getTimeBegin());
		query.ge(search.getTimeEnd() != null, RewardInfo::getDate, search.getTimeEnd());
		query.eq(search.getVillagerId() != null, RewardInfo::getVillagerId, search.getVillagerId());
		query.eq(search.getTeamId() != null, RewardInfo::getTeamId, search.getTeamId());
		query.eq(search.getPunishment() != null, RewardInfo::getPunishment, search.getPunishment());
		//query.isNotNull(RewardInfo::getCheckUser);
		return super.page(page, query);
	}

	@Override
	public boolean updateReward(RewardUpdate rewardUpdate) {
		//先保存事件
		LambdaUpdateWrapper<RewardEvent> eventUpdate = Wrappers.lambdaUpdate();
		eventUpdate.eq(RewardEvent::getId, rewardUpdate.getEventId());
		eventUpdate.set(rewardUpdate.getEventDesc() != null, RewardEvent::getEventDesc, rewardUpdate.getEventDesc());
		eventUpdate.set(rewardUpdate.getEventTime() != null, RewardEvent::getEventTime, rewardUpdate.getEventTime());
		eventUpdate.set(rewardUpdate.getAddress() != null, RewardEvent::getAddress, rewardUpdate.getAddress());
		eventUpdate.set(rewardUpdate.getEventTime() != null, RewardEvent::getYear, rewardUpdate.getEventTime().getYear());
		eventUpdate.set(rewardUpdate.getEventTime() != null, RewardEvent::getMonth, rewardUpdate.getEventTime().getMonthValue());
		rewardEventService.update(eventUpdate);
		if (rewardUpdate.getFiles() != null && rewardUpdate.getFiles().length > 0) {
			//再保存图片
			imageService.saveFiles(1, rewardUpdate.getEventId(), rewardUpdate.getFiles());
		}
		if (rewardUpdate.getSign() != null) {
			//保存签名
			imageService.saveFiles(2, rewardUpdate.getEventId(), rewardUpdate.getSign());
		}
		//最后保存红黑榜
		LambdaUpdateWrapper<RewardInfo> update = Wrappers.lambdaUpdate();
		update.eq(RewardInfo::getId, rewardUpdate.getId());
		update.set(rewardUpdate.getWelfareId() != null, RewardInfo::getWelfareId, rewardUpdate.getWelfareId());
//		update.set(rewardUpdate.getWelfareId() != null, RewardInfo::getAmountFamily, getAmountFamily());
//		update.set(rewardUpdate.getWelfareId() != null, RewardInfo::getAmountTeam, getAmountTeam());
		update.set(rewardUpdate.getTeamId() != null, RewardInfo::getTeamId, rewardUpdate.getTeamId());
		update.set(rewardUpdate.getFamilyId() != null, RewardInfo::getFamilyId, rewardUpdate.getFamilyId());
		update.set(rewardUpdate.getUser() != null, RewardInfo::getVillagerId, rewardUpdate.getUser());
		update.set(rewardUpdate.getEventTime() != null, RewardInfo::getDate, rewardUpdate.getEventTime());
		update.set(rewardUpdate.getEventTime() != null, RewardInfo::getYear, rewardUpdate.getEventTime().getYear());
		update.set(rewardUpdate.getEventTime() != null, RewardInfo::getMonth, rewardUpdate.getEventTime().getMonthValue());
		update.set(rewardUpdate.getPunishment() != null, RewardInfo::getPunishment, rewardUpdate.getPunishment());
		super.update(update);
		nextStep(rewardEventService.getById(rewardUpdate.getEventId()), super.getById(rewardUpdate.getId()));
		return true;
	}

	@Override
	public boolean accessReward(Long rewardId, String checkName) {
		LambdaUpdateWrapper<RewardInfo> update = Wrappers.lambdaUpdate();
		update.eq(RewardInfo::getId, rewardId);
		update.set(RewardInfo::getCheckUser, checkName);
		super.update(update);
		//更新金额记录表
		RewardInfo info = super.getById(rewardId);
		collectInfoService.accessReward(info.getEventId());
		return true;
	}

	@Override
	public boolean updateRewardAmount(Long eventId, BigDecimal amountFamily, BigDecimal amountTeam) {
		LambdaUpdateWrapper<RewardInfo> update = Wrappers.lambdaUpdate();
		update.eq(RewardInfo::getEventId, eventId);
		update.set(RewardInfo::getAmountFamily, amountFamily);
		update.set(RewardInfo::getAmountTeam, amountTeam);
		return super.update(update);
	}


	@Override
	public Integer countByYear(Integer year, Integer punishment) {
		LambdaQueryWrapper<RewardInfo> query = Wrappers.lambdaQuery();
		query.eq(year != null, RewardInfo::getYear, year);
		query.eq(punishment != null, RewardInfo::getPunishment, punishment);
		//query.isNotNull(RewardInfo::getCheckUser);
		return super.count(query);
	}

	@Override
	public Integer countByMonth(Integer year, Integer month, Integer punishment) {
		LambdaQueryWrapper<RewardInfo> query = Wrappers.lambdaQuery();
		query.eq(year != null, RewardInfo::getYear, year);
		query.eq(month != null, RewardInfo::getMonth, month);
		query.eq(punishment != null, RewardInfo::getPunishment, punishment);
		//query.isNotNull(RewardInfo::getCheckUser);
		return super.count(query);
	}

	@Override
	public List<MainReward> mainRewardList(Integer year, Integer punishment) {
		if (year == null) {
			year = DateUtil.thisYear();
		}
		//按照月分组统计
		LambdaQueryWrapper<RewardInfo> query = Wrappers.lambdaQuery();
		query.eq(year != null, RewardInfo::getYear, year);
		query.eq(punishment != null, RewardInfo::getPunishment, punishment);
		List<RewardInfo> rewardInfos = super.list(query);
		Map<String, Long> rewardMap = rewardInfos.stream().collect(Collectors.groupingBy(e -> "" + e.getYear() + e.getMonth() + e.getPunishment(), Collectors.counting()));
		List<MainReward> result = new ArrayList<>();
		MainReward mainReward = null;
		for (int i = 1; i <= 12; i++) {
			String key = "" + year + i;
			//处理punishment
			if (punishment != null) {
				mainReward = MainReward.builder().year(year).month(i).build();
				//处理punishment
				int count = rewardMap.get(key + punishment) == null ? 0 : rewardMap.get(key + punishment).intValue();
				mainReward.setCount(count);
				mainReward.setPunishment(punishment);
				result.add(mainReward);
				continue;
			}
			//此时未指定punishment！
			//红榜数据
			mainReward = MainReward.builder().year(year).month(i).build();
			int count1 = rewardMap.get(key + 0) == null ? 0 : rewardMap.get(key + 0).intValue();
			mainReward.setCount(count1);
			mainReward.setPunishment(0);
			result.add(mainReward);
			//黑榜数据
			mainReward = MainReward.builder().year(year).month(i).build();
			int count2 = rewardMap.get(key + 1) == null ? 0 : rewardMap.get(key + 1).intValue();
			mainReward.setCount(count2);
			mainReward.setPunishment(1);
			result.add(mainReward);
		}
		return result;
	}

	@Override
	public List<RewardInfo> listByCondition(Integer year, Integer punishment) {
		//默认查询今年的黑榜事件
		year = year == null ? DateUtil.thisYear() : year;
		punishment = punishment == null ? 1 : punishment;
		LambdaQueryWrapper<RewardInfo> query = Wrappers.lambdaQuery();
		query.eq(RewardInfo::getYear, year);
		query.eq(RewardInfo::getPunishment, punishment);
		List<RewardInfo> rewardInfos = super.list(query);
		return rewardInfos;
	}

	@Override
	public List<RewardInfo> listByEvent(RewardEvent event) {
		LambdaQueryWrapper<RewardInfo> query = Wrappers.lambdaQuery();
		query.eq(RewardInfo::getEventId, event.getId());
		return super.list(query);
	}
}
